import { Component, Input, Output, EventEmitter, ViewChild, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';

import { Configuration } from '../config';
import {
    ScanningResultService,
    SystemInfo,
    SystemInfoService,
    ConfigurationService
} from '../../service/index';
import { ErrorHandler } from '../../error-handler/index';
import { toPromise, isEmptyObject, clone} from '../../utils';
import { TranslateService } from '@ngx-translate/core';
import { ClairDetail } from '../../service/interface';
const ONE_HOUR_SECONDS: number = 3600;
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
const SCHEDULE_TYPE = {
    NONE: "none",
    DAILY: "daily"
};
@Component({
    selector: 'vulnerability-config',
    templateUrl: './vulnerability-config.component.html',
    styleUrls: ['./vulnerability-config.component.scss', '../registry-config.component.scss']
})
export class VulnerabilityConfigComponent implements OnInit {
    _localTime: Date = new Date();
    isEditMode: boolean = false;
    SCHEDULE_TYPE = SCHEDULE_TYPE;
    configCopy: Configuration;
    onSubmitting: boolean = false;
    config: Configuration;
    openState: boolean = false;
    @Output() configChange: EventEmitter<Configuration> = new EventEmitter<Configuration>();

    @Input()
    get vulnerabilityConfig(): Configuration {
        return this.config;
    }
    set vulnerabilityConfig(cfg: Configuration) {
        this.config = cfg;
        if (this.config.scan_all_policy &&
            this.config.scan_all_policy.value) {
            if (this.config.scan_all_policy.value.type === "daily") {
                if (!this.config.scan_all_policy.value.parameter) {
                    this.config.scan_all_policy.value.parameter = {
                        daily_time: 0
                    };
                }
            }
        }
        this.configChange.emit(this.config);
    }

    @Input() showSubTitle: boolean = false;
    @Input() showScanningNamespaces: boolean = false;
    systemInfo: SystemInfo;

    constructor(
        private scanningService: ScanningResultService,
        private errorHandler: ErrorHandler,
        private translate: TranslateService,
        private systemInfoService: SystemInfoService,
        private configService: ConfigurationService
    ) { }

    get scanAvailable(): boolean {
        return !this.onSubmitting;
    }

    get updatedTimestamp(): Date {
        if (this.systemInfo &&
            this.systemInfo.clair_vulnerability_status &&
            this.systemInfo.clair_vulnerability_status.overall_last_update > 0) {
            return this.convertToLocalTime(this.systemInfo.clair_vulnerability_status.overall_last_update);
        }

        return null;
    }

    get namespaceTimestamps(): ClairDetail[] {
        if (this.systemInfo &&
            this.systemInfo.clair_vulnerability_status &&
            this.systemInfo.clair_vulnerability_status.details &&
            this.systemInfo.clair_vulnerability_status.details.length > 0) {
            return this.systemInfo.clair_vulnerability_status.details;
        }

        return [];
    }

    // UTC time
    get dailyTime(): string {
        if (!(this.config &&
            this.config.scan_all_policy &&
            this.config.scan_all_policy.value &&
            this.config.scan_all_policy.value.type === "daily")) {
            return "00:00";
        }

        let timeOffset: number = 0; // seconds
        if (this.config.scan_all_policy.value.parameter) {
            let daily_time = this.config.scan_all_policy.value.parameter.daily_time;
            if (daily_time && typeof daily_time === "number") {
                timeOffset = +daily_time;
            }
        }
        // Convert to current time
        let timezoneOffset: number = this._localTime.getTimezoneOffset();
        // Local time
        timeOffset = timeOffset - timezoneOffset * 60;
        if (timeOffset < 0) {
            timeOffset = timeOffset + ONE_DAY_SECONDS;
        }

        if (timeOffset >= ONE_DAY_SECONDS) {
            timeOffset -= ONE_DAY_SECONDS;
        }

        // To time string
        let hours: number = Math.floor(timeOffset / ONE_HOUR_SECONDS);
        let minutes: number = Math.floor((timeOffset - hours * ONE_HOUR_SECONDS) / 60);

        let timeStr: string = "" + hours;
        if (hours < 10) {
            timeStr = "0" + timeStr;
        }
        if (minutes < 10) {
            timeStr += ":0";
        } else {
            timeStr += ":";
        }
        timeStr += minutes;

        return timeStr;
    }
    set dailyTime(v: string) {
        if (!v || v === "") {
            return;
        }

        if (!(this.config &&
            this.config.scan_all_policy &&
            this.config.scan_all_policy.value &&
            this.config.scan_all_policy.value.type === "daily")) {
            return;
        }

        // Double confirm inner parameter existing.
        if (!this.config.scan_all_policy.value.parameter) {
            this.config.scan_all_policy.value.parameter = {
                daily_time: 0
            };
        }

        let values: string[] = v.split(":");
        if (!values || values.length !== 2) {
            return;
        }

        let hours: number = +values[0];
        let minutes: number = +values[1];
        // Convert to UTC time
        let timezoneOffset: number = this._localTime.getTimezoneOffset();
        let utcTimes: number = hours * ONE_HOUR_SECONDS + minutes * 60;
        utcTimes += timezoneOffset * 60;
        if (utcTimes < 0) {
            utcTimes += ONE_DAY_SECONDS;
        }

        if (utcTimes >= ONE_DAY_SECONDS) {
            utcTimes -= ONE_DAY_SECONDS;
        }

        this.config.scan_all_policy.value.parameter.daily_time = utcTimes;
    }

    // Scanning type
    get scanningType(): string {
        if (this.config &&
            this.config.scan_all_policy &&
            this.config.scan_all_policy.value) {
            return this.config.scan_all_policy.value.type;
        } else {
            // default
            return "none";
        }
    }


    set scanningType(v: string) {
        if (this.config &&
            this.config.scan_all_policy &&
            this.config.scan_all_policy.value) {
            let type: string = (v && v.trim() !== "") ? v : "none";
            this.config.scan_all_policy.value.type = type;
            if (type !== "daily") {
                // No parameter
                if (this.config.scan_all_policy.value.parameter) {
                    delete (this.config.scan_all_policy.value.parameter);
                }
            } else {
                // Has parameter
                if (!this.config.scan_all_policy.value.parameter) {
                    this.config.scan_all_policy.value.parameter = {
                        daily_time: 0
                    };
                }
            }
        }
    }

    @ViewChild("systemConfigFrom") systemSettingsForm: NgForm;

    get editable(): boolean {
        return this.vulnerabilityConfig &&
            this.vulnerabilityConfig.scan_all_policy &&
            this.vulnerabilityConfig.scan_all_policy.editable;
    }

    get isValid(): boolean {
        return this.systemSettingsForm && this.systemSettingsForm.valid;
    }

    get showTimePicker(): boolean {
        return this.vulnerabilityConfig &&
            this.vulnerabilityConfig.scan_all_policy &&
            this.vulnerabilityConfig.scan_all_policy.value &&
            this.vulnerabilityConfig.scan_all_policy.value.type === "daily";
    }

    get isClairDBFullyReady(): boolean {
        return this.systemInfo &&
            this.systemInfo.clair_vulnerability_status &&
            this.systemInfo.clair_vulnerability_status.overall_last_update > 0;
    }

    ngOnInit(): void {
        this.getSystemInfo();
        this.getConfigurations();
    }

    getConfigurations(): void {
        toPromise<Configuration>(this.configService.getConfigurations())
            .then((config: Configuration) => {
                this.configCopy = clone(config);
                this.config = config;
            })
            .catch(error => {
                this.errorHandler.error(error);
            });
    }

    editSchedule() {
        this.isEditMode = true;
     }

    convertToLocalTime(utcTime: number): Date {
        let dt: Date = new Date();
        dt.setTime(utcTime * 1000);

        return dt;
    }

    scanNow(): void {
        if (this.onSubmitting) {
            return; // Aoid duplicated submitting
        }

        if (!this.scanAvailable) {
            return; // Aoid page hacking
        }

        this.onSubmitting = true;
        toPromise<any>(this.scanningService.startScanningAll())
            .then(() => {
                this.translate.get("CONFIG.SCANNING.TRIGGER_SCAN_ALL_SUCCESS").subscribe((res: string) => {
                    this.errorHandler.info(res);
                });

                // Update system info
                this.getSystemInfo().then(() => {
                    this.onSubmitting = false;
                }).catch(() => {
                    this.onSubmitting = false;
                });
            })
            .catch(error => {
                if (error && error.status && error.status === 412) {
                    this.translate.get("CONFIG.SCANNING.TRIGGER_SCAN_ALL_FAIL", { error: '' + error }).subscribe((res: string) => {
                        this.errorHandler.error(res);
                    });
                } else {
                    this.errorHandler.error(error);
                }
                this.onSubmitting = false;
            });
    }

    getSystemInfo(): Promise<void | SystemInfo> {
        return toPromise<SystemInfo>(this.systemInfoService.getSystemInfo())
            .then((info: SystemInfo) => this.systemInfo = info)
            .catch(error => this.errorHandler.error(error));
    }

    save(): void {
        let getchanges = this.config.scan_all_policy.value;
        let changes = {"scan_all_policy": getchanges};

        if (isEmptyObject(changes)) {
            return;
        }

        toPromise<any>(this.configService.saveConfigurations(changes))
            .then(() => {
                this.translate.get("CONFIG.SAVE_SUCCESS").subscribe((res: string) => {
                    this.errorHandler.info(res);
                });
                this.getConfigurations();
                this.isEditMode = false;
            }, () => {
                this.reset();
            })
            .catch(error => {
                this.errorHandler.error(error);
                this.reset();
            });
    }

    cancel(): void {
        this.reset();
        this.isEditMode = false;
    }

    reset(): void {
        // Reset to the values of copy
        let getchanges = this.config.scan_all_policy.value;
        let changes = {"scan_all_policy": getchanges};
        for (let prop of Object.keys(changes)) {
            this.config[prop] = clone(this.configCopy[prop]);
        }
    }
}
